; void rotar_asm (
; 	unsigned char *src,
; 	unsigned char *dst,
; 	int m,
; 	int n,
; 	int src_row_size,
; 	int dst_row_size
; );

; Parámetros:
; 	rdi = src
; 	rsi = dst
; 	rdx = m
; 	rcx = n
; 	r8 = src_row_size
; 	r9 = dst_row_size


global rotar_asm
section .data
    CURRENT_MXCSR DD 0      ;place to keep the current value of MXCSR

section .text

rotar_asm:
    PUSH RBP
    MOV RBP,RSP
    PUSH RBX
    PUSH R12
    PUSH R13
    PUSH R14
    PUSH R15
    SUB RSP, 8

    xor r10, r10  ; r10 indice columna
    xor r11, r11  ; r11 indice fila
    mov r12, rdi  ; r12: *origen
    mov r13, rsi  ; r13: *destino
    mov r14, rdx  ; r14: m
    mov r15, rcx  ; r15: n

    lea rsi, [CURRENT_MXCSR]
    STMXCSR [rSI]           ;store the MXCSR into memory
    MOV EAX,[rSI]           ;put into EAX
    OR AH,60h               ;set rounding chop (truncate)
    MOV [rSI],EAX           ;put back into memory
    LDMXCSR [rSI]           ;and put that into processor


    ciclo:
        mov rax, r10
        add rax, 4
        cmp rax, r15        ; indice_col + 16 > cant_columnas ?
        jbe seguir
        lea r10, [r15 - 4]
    seguir:

    mov rdi, r10
    mov rsi, r11
    mov rdx, r15
    mov rcx, r14
    call calcular_u     ; en xmm0: u1 | u2 | u3 | u4
    movdqu xmm7, xmm0   ; xmm7: u
    
    mov rdi, r10
    mov rsi, r11
    mov rdx, r15
    mov rcx, r14
    call calcular_v         ; en xmm0: v1 | v2 | v3 | v4
    
    pxor xmm1, xmm1         ; xmm1: 0
    pinsrd xmm2, r14d, 0
    shufps xmm2, xmm2, 0h   ; xmm2: m | m | m | m
    pinsrd xmm3, r15d, 0  
    shufps xmm3, xmm3, 0    ; xmm3: n | n | n | nh


    pcmpgtd xmm3, xmm7      ; xmm3: n > u 
    movdqu xmm4, xmm7       ; xmm4: u
    pcmpgtd xmm4, xmm1      ; xmm4: u > 0
    
    movdqu xmm5, xmm7       ; xmm5: u
    pcmpeqd xmm5, xmm1      ; xmm5: u == 0

    por xmm4, xmm5
    
    
    pand xmm3, xmm4         ; xmm3: n > u >= 0

    pcmpgtd xmm2, xmm0      ; xmm2: m > v
    movdqu xmm4, xmm0       ; xmm4: v
    pcmpgtd xmm4, xmm1      ; xmm4: v > 0
    
    movdqu xmm5, xmm0
    pcmpeqd xmm5, xmm1      ; xmm5: v == 0

    por xmm4, xmm5          ; xmm4: v >= 0


    pand xmm2, xmm4         ; xmm2: m > v >= 0

    pand xmm2, xmm3         ; xmm2: m > v > 0 && n > u > 0

    movq rdi, xmm2          ; rdi: m1 | m2
    movhlps xmm2, xmm2
    movq rsi, xmm2          ; rsi: m3 | m4

    xor ecx, ecx        ;en ecx voy a poner el resultado
    
    
    mov rbx, rsi        ; rbx: m3 m4
    shr rbx, 32         ; rbx: m4
    cmp ebx, 0xFFFFFFFF
    jne no_m4

    ; copio imagen para la 4ta posicion
                        ; xmm7: u1|u2|u3|u4
    movhlps xmm2, xmm7  ; xmm2: u3|u4|xx|xx
    movq rbx, xmm2      ; rbx: u3u4
    shr rbx, 32         ; ebx: u4
    movhlps xmm2, xmm0  ; xmm2: v3|v4|xx|xx
    movq rax, xmm2
    shr rax, 32         ; eax: v4
    mul r8d             ; rax v4 * src_row_size
    add eax, ebx        ; eax: ..... + u4

    mov cl, [r12 + rax]

    no_m4:
    shl ecx, 8          ; shifteo para dejar lugar al siguiente dato
    cmp esi, 0xFFFFFFFF     ; m3 == true ?
    jne no_m3

    ; copio la imagen para la 3ra posicion

    movhlps xmm2, xmm7  ; xmm2: u3|u4|xx|xx
    xor rbx, rbx
    movd ebx, xmm2      ; ebx: u3
    movhlps xmm2, xmm0
    movd eax, xmm2      ; eax: v3

    mul r8d
    add eax, ebx    
    mov cl, [r12 + rax]

    no_m3:
    shl ecx, 8
    mov rbx, rdi
    shr rbx, 32
    cmp ebx, 0xFFFFFFFF
    jne no_m2

    ; copio para la 2da posicion
    movq rbx, xmm7      ; rbx: u1|u2
    shr rbx, 32         ; rbx: u2 00
    movq rax, xmm0      ; rax: v1 v2
    shr rax, 32         ; rax: v2

    mul r8d
    add eax, ebx
    mov cl, [r12 + rax]

    no_m2:
    shl ecx, 8
    cmp edi, 0xFFFFFFFF
    jne no_m1

    ; copio para la 1ra posicion
    xor ebx, ebx
    xor eax, eax
    
    movd ebx, xmm7      ; ebx: u1
    movd eax, xmm0      ; eax: v1
    
    mul r8d
    add eax, ebx
    mov cl, [r12 + rax]

    no_m1:
    ; escribo
    mov eax, r11d
    mul r9d             ; eax: indice_fila * dst_row_size
    add rax, r10


    mov [r13 + rax], ecx


    add r10, 4
    cmp r10, r15
    jb ciclo

    xor r10, r10
    inc r11
    
    cmp r11, r14
    jb ciclo

    ADD RSP, 8
    POP R15
    POP R14
    POP R13
    POP R12
    POP RBX
    POP RBP

    ret


calcular_u:
    ; rdi = indice_columna
    ; rsi = indice_fila
    ; rdx = ancho imagen
    ; rcx = alto imagen
    call calcular_interno

    ; xmm0: (i_col - ancho/2)
    ; xmm1: (i_fila - alto/2)
    ; xmm2: ancho/2 = c_x
    ; xmm4: sqrt(2)/2

    subps xmm0, xmm1    
    mulps xmm0, xmm4       ; xmm0: sqrt(2)/2 * (x - c_x - y + c_y)


    addps xmm2, xmm0       ; c_x + xmm0 

    cvtps2dq xmm2, xmm2
    
    movdqu xmm0, xmm2
    ret

calcular_v:
    call calcular_interno

    addps xmm0, xmm1
    mulps xmm0, xmm4
    addps xmm3, xmm0
    
    cvtps2dq xmm3, xmm3
    movdqu xmm0, xmm3
    ret

calcular_interno:
    pinsrd xmm0, edi, 0    ; indice col
    inc edi
    pinsrd xmm0, edi, 1
    inc edi
    pinsrd xmm0, edi, 2
    inc edi
    pinsrd xmm0, edi, 3
                            ; xmm0: i_col, i_col+1, i_col+2, i_col+3

    pinsrd xmm1, esi, 0
    shufps xmm1, xmm1, 0h   ; xmm1: i_fila, i_fila, i_fila, i_fila

    pinsrd xmm2, edx, 0
    shufps xmm2, xmm2, 0h   ; xmm2: ancho, ancho, ancho.
    pinsrd xmm3, ecx, 0
    shufps xmm3, xmm3, 0h   ; xmm3: alto, alto alto

    psrad xmm2, 1           ; xmm2: ancho/2
    psrad xmm3, 1           ; xmm3: alto/2

    mov eax, 2
    pinsrd xmm4, eax, 0
    shufps xmm4, xmm4, 0h

    ;paso todo a float
    cvtdq2ps xmm2, xmm2
    cvtdq2ps xmm3, xmm3
    cvtdq2ps xmm0, xmm0
    cvtdq2ps xmm1, xmm1
    cvtdq2ps xmm4, xmm4

    movdqu xmm5, xmm4       ; xmm5: 2
    sqrtps xmm4, xmm4       ; xmm4: sqrt(2)
    divps xmm4, xmm5        ; xmm4: sqrt(2)/2


    subps xmm0, xmm2        ; xmm0: i_col - ancho/2
    subps xmm1, xmm3        ; xmm1: i_fila - alto/2





    ret
